package comet

import (
	"fmt"
	"gitee.com/haozing/wim/comet/iface"
	"gitee.com/haozing/wim/comet/internal"
	"github.com/bwmarrin/snowflake"
	"github.com/gobwas/ws"
	"net"
)

const maxConcurrentConnection = 100000

// ServerConfig Server服务配置
type ServerConfig struct {
	//服务器的名称
	Name string
	//tcp4 or other
	IPVersion  string
	ServerType string
	//服务绑定的IP地址
	IP string
	//服务绑定的端口
	Port int
}

//Server服务类 IServer实现

type Server struct {
	//服务器的名称
	Name string
	//tcp4 or other
	IPVersion string
	//类型tcp、http、https、websocket、websockets
	serverType string
	//服务绑定的IP地址
	IP string
	//服务绑定的端口
	Port int
	//消息管理
	EventHandler iface.IEventHandler
	//当前Server的链接管理器
	ConnMgr iface.IConnManager
	//该Server的连接创建时Hook函数
	OnConnStart func(conn iface.IConnection)
	//该Server的连接断开时的Hook函数
	OnConnStop func(conn iface.IConnection)
	//使用雪花算法生成id
	Snowflake *snowflake.Node
}

func (s *Server) ServerType() string {
	return s.serverType
}

func (s *Server) PreWrite() {
	// PreWrite会在将任何数据写入任何客户端套接字之前触发，此事件函数通常用于
	//在将数据写入客户端之前放置一些日志记录，计数/报告或任何前置操作代码。
	s.EventHandler.PreWrite()
}

func (s *Server) OnClosed(c iface.IConnection) (action iface.Action) {
	return s.EventHandler.OnClosed(c)
}

func (s *Server) OnShutdown() {
	s.EventHandler.OnShutdown(s)
}

// ConnCodec 创建协议
func (s *Server) ConnCodec(c iface.IConnection) {
	c.InitCodec(s.EventHandler.Codec())
}

// NewServer 创建一个服务器句柄
func NewServer(c *ServerConfig, e iface.IEventHandler) iface.IServer {
	node, err := snowflake.NewNode(1)
	if err != nil {
		panic("Failed to initialize snowflake")
	}
	s := &Server{
		Name:         c.Name,
		IPVersion:    c.IPVersion,
		serverType:   c.ServerType,
		IP:           c.IP,
		Port:         c.Port,
		ConnMgr:      internal.NewConnManager(),
		EventHandler: e,
		Snowflake:    node,
	}
	return s
}
func (s *Server) Stop() {
	fmt.Println("[STOP] server , name ", s.Name)

	//将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
	s.ConnMgr.ClearConn()
}

func (s *Server) Serve() {
	//服务器准备好接受连接时，将触发OnInitComplete。
	//参数：server具有信息和各种实用程序。
	s.EventHandler.OnInitComplete(s)
	s.Start()

	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加

}
func (s *Server) OnEvent() iface.IEventHandler {
	return s.EventHandler
}
func (s *Server) GetConnMgr() iface.IConnManager {
	return s.ConnMgr
}

func (s *Server) Process(b []byte, c iface.IConnection) {
	s.EventHandler.Process(b, c)
}

func (s *Server) SendMsgPl(connId int64, b []byte) {
	conn, err := s.GetConnMgr().Get(connId)
	if err != nil {
		return
	}
	err = conn.SendBuffMsg(true, b)
	if err != nil {
		return
	}
}

// Start 开启网络服务
func (s *Server) Start() {
	fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)

	//开启一个go去做服务端Listen业务
	go func() {
		//2 监听服务器地址
		listener, err := net.Listen(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}

		//已经监听成功
		fmt.Println("start server  ", s.Name, " success, now listening...")

		//3 启动server网络连接业务
		for {
			//3.1 阻塞等待客户端建立连接请求
			conn, err := listener.Accept()
			if err != nil {
				fmt.Println("Accept err ", err)
				continue
			}

			//3.2 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接
			if s.ConnMgr.Len() >= maxConcurrentConnection {
				err = conn.Close()
				if err != nil {
					return
				}
				continue
			}

			var opcode ws.OpCode
			if s.serverType == "websocket" {
				h, err := ws.Upgrade(conn)
				if err != nil {
					fmt.Println("websocket ws.Upgrade(conn) ", err)
					continue
				}
				if h.Protocol == "" {
					opcode = ws.OpText
				}
			}
			fmt.Println("Get conn remote addr = ", conn.RemoteAddr().String())
			//3.3 处理该新连接请求的 业务 方法， 此时应该有 handler 和 conn是绑定的
			dealConn := internal.NewConnection(s, conn, s.Snowflake.Generate().Int64(), opcode)

			//3.4 启动当前链接的处理业务
			go dealConn.Start()

		}
	}()

}
